/*
 * @Author: 大D
 * @email: 857216393@qq.com
 * @Date: 2024-01-26 10:20:42
 * @Description: 拖拽指令  在指定范围 #drag-box 或者 可视区域内
 * @param {*} top left 设置初始位置
 *  v-drag="{ top, left }"
 */

import type { Directive, DirectiveBinding } from 'vue';

const drag: Directive = {
  mounted: (el: HTMLElement, binding: DirectiveBinding) => {
    // 获取可视区域宽高  不可移出可视区域范围
    // 如果存在#drag-box 则规定范围在盒子内
    const dragBox = document.getElementById('drag-box');
    let minWidth: number, maxWidth: number, minHeight: number, maxHeight: number;
    if (dragBox) {
      minHeight = dragBox.getBoundingClientRect().top; // 元素上边距离页面可视区上边的距离
      minWidth = dragBox.getBoundingClientRect().left; // 元素左边距离页面可视区左边的距离
      maxWidth = dragBox.clientWidth + minWidth;
      maxHeight = dragBox.clientHeight + minHeight;
    } else {
      minHeight = 0; // 元素上边距离页面可视区上边的距离
      minWidth = 0; //
      maxWidth = window.innerWidth || document.documentElement.clientWidth;
      maxHeight = window.innerHeight || document.documentElement.clientHeight;
    }
    // 设置目标元素基础属性
    el.style.cursor = 'move';
    el.style.position = 'absolute';
    el.style.zIndex = '9999';
    if (binding.value) {
      el.style.top = binding.value.top + 'px';
      el.style.left = binding.value.left + 'px';
    }
    let mouseX: number, mouseY: number, width: number, height: number, left: number, top: number;
    // 处理鼠标按下或触摸开始事件
    const handleMouseDown = (e: MouseEvent | TouchEvent) => {
      width = el.getBoundingClientRect().width;
      height = el.getBoundingClientRect().height;
      // 当前目标元素的left与top
      left = el.offsetLeft + minWidth;
      top = el.offsetTop + minHeight;
      // 保存按下的鼠标的X与Y
      mouseX = 'touches' in e ? e.targetTouches[0].clientX : e.clientX;
      mouseY = 'touches' in e ? e.targetTouches[0].clientY : e.clientY;
      // 监听鼠标移动
      document.addEventListener('mousemove', handleMouseMove, {
        passive: false // 阻止默认滚动行为
      });
      document.addEventListener('touchmove', handleMouseMove, {
        passive: false // 阻止默认滚动行为
      });
      // 添加鼠标松开和触摸结束事件监听器
      document.addEventListener('mouseup', handleMouseUp);
      document.addEventListener('touchend', handleMouseUp);
    };
    // 处理鼠标松开或触摸结束事件
    const handleMouseUp = () => {
      // 移除事件的监听器
      document.removeEventListener('touchmove', handleMouseMove);
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
      document.removeEventListener('touchend', handleMouseUp);
    };
    // 处理鼠标移动或触摸移动事件
    const handleMouseMove = (e: MouseEvent | TouchEvent) => {
      // 鼠标移动的距离
      const x = 'touches' in e ? e.targetTouches[0].clientX : e.clientX;
      const y = 'touches' in e ? e.targetTouches[0].clientY : e.clientY;
      let disX = x - mouseX;
      let disY = y - mouseY;
      let lastLeft = 0;
      if (left + disX <= minWidth) {
        lastLeft = minWidth;
      } else if (left + disX >= maxWidth - width) {
        lastLeft = maxWidth - width;
      } else {
        lastLeft = left + disX;
      }
      let lastTop = 0;
      if (top + disY <= minHeight) {
        lastTop = minHeight;
      } else if (top + disY >= maxHeight - height) {
        lastTop = maxHeight - height;
      } else {
        lastTop = top + disY;
      }
      lastLeft = lastLeft - minWidth;
      lastTop = lastTop - minHeight;
      el.style.left = lastLeft + 'px';
      el.style.top = lastTop + 'px';
      return false; // 防止选中文本，文本拖动的问题
    };
    // 监听鼠标在目标元素上按下
    el.addEventListener('touchstart', handleMouseDown);
    el.addEventListener('mousedown', handleMouseDown);
  }
};

export default drag;
